package com.yyfax.pay.depository.service.inner.impl;

import java.util.Date;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.framework.yyfax.CryptUtil;
import com.yyfax.framework.yyfax.enums.YesNoEnum;
import com.yyfax.pay.common.constants.FuiouDepositConstant;
import com.yyfax.pay.common.constants.PayConstants;
import com.yyfax.pay.common.enums.FuiouBusiTypeEnum;
import com.yyfax.pay.common.enums.FuiouDepositStateEnum;
import com.yyfax.pay.common.enums.PayRspCodeEnum;
import com.yyfax.pay.common.enums.PaymentEnum;
import com.yyfax.pay.common.exception.PayException;
import com.yyfax.pay.common.exception.PayExceptionCode;
import com.yyfax.pay.common.model.vo.PayRspCodeVO;
import com.yyfax.pay.common.model.vo.ValidResult;
import com.yyfax.pay.common.util.FuiouIdUtils;
import com.yyfax.pay.config.data.service.BankConfigExtService;
import com.yyfax.pay.config.data.service.BankConfigService;
import com.yyfax.pay.config.model.po.BankConfigExtPO;
import com.yyfax.pay.config.model.po.BankConfigPO;
import com.yyfax.pay.depository.dao.FuiouArtificialRegisterDao;
import com.yyfax.pay.depository.dao.FuiouUserRegisterDao;
import com.yyfax.pay.depository.domain.EnterpriseAuth;
import com.yyfax.pay.depository.domain.FuiouArtificialRegister;
import com.yyfax.pay.depository.domain.FuiouUserRegister;
import com.yyfax.pay.depository.service.inner.FuiouDepositCommonService;
import com.yyfax.pay.depository.service.inner.FuiouDepositRegisterService;
import com.yyfax.pay.depository.vo.ArtificialRegisterVO;
import com.yyfax.pay.depository.vo.UserRegisterVO;
import com.yyfax.pay.order.data.service.EnterpriseAuthService;
import com.yyfax.pay.order.data.service.UserAuthService;
import com.yyfax.pay.order.data.service.UserPaymentService;
import com.yyfax.pay.order.model.po.UserAuthPO;
import com.yyfax.pay.order.model.po.UserPaymentPO;
import com.yyfax.pay.third.facade.fuioudeposit.FuiouDepositService;
import com.yyfax.pay.vo.depository.ArtificialRegisterReq;
import com.yyfax.pay.vo.depository.UserRegisterReq;

/**
 * @author yejc
 * @date 2017-09-02
 * @since v2.0.0
 */
@Service
public class FuiouDepositRegisterServiceImpl implements FuiouDepositRegisterService {

	protected Logger logger = LoggerFactory.getLogger(getClass());
	@Resource
	private FuiouIdUtils fuiouIdUtils;
	@Resource
	private FuiouUserRegisterDao userRegisterDao;
	@Resource
	private FuiouArtificialRegisterDao artificialRegisterDao;
	@Resource
	private FuiouDepositService fuiouDepositService;
	@Resource
	private BankConfigExtService bankConfigExtService;
	@Resource
	private UserAuthService userAuthService;
	@Resource
	private UserPaymentService userPaymentService;
	@Resource
	private BankConfigService bankConfigService;
	@Resource
	private EnterpriseAuthService enterpriseAuthService;
	@Resource
	private FuiouDepositCommonService commonService;

	/**
	 * 校验普通用户开户请求
	 * 
	 * @author buyi
	 * @date 2018-01-12 15:32:55
	 * @since 2.0.0
	 * @param merchantCode
	 * @param userRegisterReq
	 * @return
	 * @throws Exception
	 */
	@Override
	public ValidResult validateUserRegister(String merchantCode, UserRegisterReq userRegisterReq) throws Exception {
		final String op = "FuiouDepositRegisterServiceImpl.validateUserRegister";

		BankConfigExtPO bankConfigExtPO;
		try {
			bankConfigExtPO = bankConfigExtService.queryByThirdBankCode(userRegisterReq.getBankCode(), PaymentEnum.FUIOU_DEPOSIT.getValue());
			if (bankConfigExtPO == null) {
				// 富友存管的银行扩展信息缺失
				// 如果能够明确知道数据异常，不抛异常，edit by buyi since 2.0.7
				// throw PayExceptionCode.ERROR_ILL_CONFIG_BANK_EXT.exp();
				return ValidResult.newInstance(false, "缺少富友存管银行扩展信息");
			}
		} catch (Exception e) {
			logger.error(Log.op(op).msg("【富友存管】【普通用户开户】查询富友存管银行扩展信息异常").kv("bankCode", userRegisterReq.getBankCode())
					.kv("payment", PaymentEnum.FUIOU_DEPOSIT.getValue()).toString(), e);
			// 如果能够明确知道数据异常，不抛异常，edit by buyi since 2.0.7
			// throw PayExceptionCode.ERROR_ILL_CONFIG_BANK_EXT.exp();
			throw e;
		}

		String fuiouBankNo = bankConfigExtPO.getBankNoExt();

		if (StringUtils.isBlank(fuiouBankNo) || fuiouBankNo.length() != 4) {
			logger.error(Log.op(op).msg("【富友存管】【普通用户开户】查询富友存管银行扩展信息银行行号异常").kv("bankCode", userRegisterReq.getBankCode())
					.kv("fuiouBankNo", fuiouBankNo).toString());
			return ValidResult.newInstance(false, "请求参数错误，不支持的银行代码");
		}

		try {

			UserAuthPO userAuthPO = userAuthService.queryByUserIdAndMerchantCode(userRegisterReq.getUserId(), merchantCode);
			if (userAuthPO != null) {
				// 四要素 验证用户幂等
				String idNoCip = CryptUtil.encrypt(userRegisterReq.getIdCard());
				String cardNoCip = CryptUtil.encrypt(userRegisterReq.getBankCardNo());
				boolean userOpenSuccess = userAuthService.checkUserOpenSuccess(merchantCode, userRegisterReq.getUserId(),
						userRegisterReq.getCustName(), idNoCip, cardNoCip, userRegisterReq.getPhone());
				if (userOpenSuccess) {
					return ValidResult.newInstance(true, PayConstants.OPEN_ACCOUNT_SUCCESS);
				}
			}
		} catch (Exception e) {
			logger.error(Log.op(op).msg("查询实名认证信息异常").kv("userId", userRegisterReq.getUserId()).kv("merchantCode", merchantCode).toString(), e);
		}

		return ValidResult.newInstance(true, null);
	}

	@Override
	public ValidResult validUserIdemptent(String merchantCode, String userId, String name, String idNo, String cardNo, String phone)
			throws Exception {
		final String op = "FuiouDepositRegisterServiceImpl.validUserIdemptent";
		String idNoCip = CryptUtil.encrypt(idNo);
		String cardNoCip = CryptUtil.encrypt(cardNo);

		// step1.校验用户实名信息
		UserAuthPO userAuthPO = userAuthService.queryByUserIdAndMerchantCode(userId, merchantCode);
		if (userAuthPO == null) {
			// 如果用户实名信息不存在，则允许继续开户
			return ValidResult.newInstance(false);
		}
		// 如果实名信息存在，则校验一直性
		if (!StringUtils.equals(userAuthPO.getName(), name) || !StringUtils.equals(userAuthPO.getIdNoCip(), idNoCip)) {
			// 如果姓名和证件号码不一致，则终止流程
			return ValidResult.newInstance(true).errCode(PayRspCodeEnum.PAY_CODE_ID_NO_ERROR.getValue())
					.errMsg(PayRspCodeEnum.PAY_CODE_ID_NO_ERROR.getDisplay());
		}

		UserPaymentPO userPaymentPO = userPaymentService.query(merchantCode, userId, PaymentEnum.FUIOU_DEPOSIT.getValue());
		if (userPaymentPO == null || YesNoEnum.NO.isValue(userPaymentPO.getState())) {
			// 如果富友存管鉴权信息不存在，或者无效，则允许继续开户
			return ValidResult.newInstance(false);
		}

		// 如果通道鉴权信息一致，则校验一直性,富友存管开户的开户手机号保存在扩展字段
		if (!StringUtils.equals(userPaymentPO.getCardNoCip(), cardNoCip) || !StringUtils.equals(userPaymentPO.getExt(), phone)) {
			// 如果姓名和证件号码不一致，则终止流程
			return ValidResult.newInstance(true).errCode(PayRspCodeEnum.PAY_CODE_AUTH_INFO_NOT_CONSISTENCY.getValue())
					.errMsg(PayRspCodeEnum.PAY_CODE_AUTH_INFO_NOT_CONSISTENCY.getDisplay());
		}

		// 用户四要素一致，则表示已经开过户，返回幂等，响应已经开户
		ValidResult result = ValidResult.newInstance(true).errCode(PayRspCodeEnum.SUCCESS.getValue()).errMsg(PayRspCodeEnum.SUCCESS.getDisplay());

		// 如果成功，找到相关成功的开户记录的业务主键
		FuiouUserRegister userRegister = userRegisterDao.selectByFourElements(merchantCode, userId, name, idNoCip, cardNoCip, phone,
				PayRspCodeEnum.SUCCESS.getValue());
		if (userRegister != null) {
			result.ext(userRegister.getBusiId());
		} else {
			logger.error(Log.op(op).msg("【富友存管普通用户开户】开户幂等，幂等响应开户成功，查询用户开户成功订单信息为空").kv("merchantCode", merchantCode).kv("userId", userId)
					.kv("name", name).kv("idNoCip", idNoCip).kv("cardNoCip", cardNoCip).kv("phone", phone).toString());
		}

		logger.info(Log.op(op).msg("【富友存管普通用户开户】已经存在开户信息，且开户信息一致，走幂等流程。").kv("merchantCode", merchantCode).kv("userId", userId).kv("name", name)
				.kv("idNoCip", idNoCip).kv("cardNoCip", cardNoCip).kv("phone", phone).toString());

		return result;
	}

	@Override
	public UserRegisterVO saveUserRegister(String merchantCode, UserRegisterReq req) throws Exception {
		final String op = "FuiouDepositRegisterServiceImpl.initUserRegister";
		boolean duplicateKeyFlag = false;

		String idNoCip = CryptUtil.encrypt(req.getIdCard());
		String cardNoCip = CryptUtil.encrypt(req.getBankCardNo());

		FuiouUserRegister order = new FuiouUserRegister();
		order.setOrderTime(req.getOrderTime());
		order.setOrderId(req.getOrderId());
		order.setMerchantCode(merchantCode);
		order.setState(FuiouDepositStateEnum.INI.getValue());
		order.setTerminal(req.getTerminal());
		order.setMerchantUserId(req.getUserId());
		String now = DateUtil.getCurrentDateTime();
		order.setCreateTime(now);
		order.setUpdateTime(now);
		order.setBusiId(fuiouIdUtils.generateBusiId(FuiouBusiTypeEnum.REGISTER, merchantCode));
		order.setCustomerName(req.getCustName());
		order.setCertifTp(req.getCertificationType());
		order.setIdNoCip(idNoCip);
		order.setCardNoCip(cardNoCip);
		order.setPhone(req.getPhone());
		order.setEmail("");
		order.setCityCode(FuiouDepositConstant.CITY_CODE_BEIJING); // 默认为北京

		// 转换银行编号为富友存管扩展的银行编号
		// BankConfigExtPO bankConfigExtPO = bankConfigExtService.queryByThirdBankCode(req.getBankCode(), PaymentEnum.FUIOU_DEPOSIT.getValue());
		// if (bankConfigExtPO == null) {
		// throw PayExceptionCode.ERROR_ILL_CONFIG_BANK_EXT.exp();
		// } else {
		// order.setBankCode(bankConfigExtPO.getBankNoExt());
		// }
		order.setBankCode(req.getBankCode());

		order.setBankName("");
		order.setPassword(req.getPassword());
		order.setLoginPassword(req.getLoginPassword());
		order.setRemark(req.getRemark());
		try {
			userRegisterDao.insert(order);
		} catch (DuplicateKeyException e) {
			logger.warn(Log.op(op).msg("订单已存在！").kv("orderId", order.getOrderId()).kv("merchantCode", merchantCode).toString(), e);
			duplicateKeyFlag = true;
		}

		if (duplicateKeyFlag) {
			order = userRegisterDao.selectByOrderIdMerchantCode(req.getOrderId(), merchantCode);
			if (order == null) {
				// 查询已有订单
				order = userRegisterDao.selectByFourElements(merchantCode, req.getUserId(), req.getCustName(), idNoCip, cardNoCip, req.getPhone(),
						null);

				if (order == null) {
					logger.warn(Log.op(op).msg("保存普通用户开户订单，主键冲突没有找到相关订单信息").kv("UserRegisterReq", req).kv("merchantCode", merchantCode).toString());
				}
			}
		}

		return UserRegisterVO.newInstance(order);
	}

	@Override
	public FuiouUserRegister normalUserRegister(UserRegisterVO vo) {
		final String op = "FuiouDepositRegisterServiceImpl.normalUserRegister";

		FuiouUserRegister po = vo.getPo();

		// 更新订单状态为处理中
		int i = userRegisterDao.updateStateByBusiId(po.getBusiId(), FuiouDepositStateEnum.DEALING.getValue(), FuiouDepositStateEnum.INI.getValue(),
				PayExceptionCode.PROCESSING.getCode(), PayExceptionCode.PROCESSING.getDesc());
		if (i <= 0) {
			// 如果更新没有命中，说明可能存在并发的情况，或者重复请求
			logger.warn(Log.op(op).msg("【富友存管普通用户开户】更新订单状态为处理中，更新命名中，直接返回订单结果状态").kv("busiId", po.getBusiId()).toString());
			return userRegisterDao.selectByPrimaryKey(po.getBusiId());
		}

		Integer rspCode = null;
		String rspMsg = "";
		String state = FuiouDepositStateEnum.FAIL.getValue();

		try {
			// 请求富友存管开户接口
			PayRspCodeVO payRsp = fuiouDepositService.normalUserRegister(po);

			if (PayExceptionCode.WARN_REQ_TIME_OUT.isCode(payRsp.getCode()) || PayExceptionCode.TO_CONFIRM.isCode(payRsp.getCode())) {
				state = FuiouDepositStateEnum.DEALING.getValue();

				// 如果响应结果是超时或者待确认，则生成查询策略
				commonService.saveQueryTask(po.getMerchantCode(), po.getBusiId(), FuiouBusiTypeEnum.REGISTER);
			} else if (PayExceptionCode.SUCCESS.isCode(payRsp.getCode())) {
				// 如果响应结果成功，更新用户鉴权信息
				state = FuiouDepositStateEnum.SUCCESS.getValue();

				// 保存鉴权信息
				saveUserAuth(po.getMerchantCode(), po.getMerchantUserId(), CryptUtil.decrypt(po.getIdNoCip()), po.getCustomerName(), po.getBankCode(),
						CryptUtil.decrypt(po.getCardNoCip()), po.getPhone());
			}

			rspCode = payRsp.getCode();
			rspMsg = payRsp.getDesc();
		} catch (PayException e) {
			rspCode = e.getCode();
			rspMsg = e.getMessage();
		} catch (Exception e) {
			logger.error(Log.op(op).msg("【富友存管普通用户开户】请求富友接口发生未知异常").kv("busiId", po.getBusiId()).toString(), e);
			rspCode = PayExceptionCode.WARN_UNKNOWN.getCode();
			rspMsg = PayExceptionCode.WARN_UNKNOWN.getDesc();
		}

		userRegisterDao.updateStateAndRspByBusiId(state, po.getBusiId(), DateUtil.getCurrentDateTime(), rspCode, rspMsg);

		po.setState(state);
		po.setRespCode(rspCode);
		po.setRespDesc(rspMsg);

		return po;
	}

	@Override
	public ValidResult validateArtificialRegister(String merchantCode, ArtificialRegisterReq req) {
		final String op = "FuiouDepositRegisterServiceImpl.validateArtificialRegister";

		BankConfigExtPO bankConfigExtPO = null;
		try {
			bankConfigExtPO = bankConfigExtService.queryByThirdBankCode(req.getBankCode(), PaymentEnum.FUIOU_DEPOSIT.getValue());
			if (bankConfigExtPO == null) {
				throw PayExceptionCode.ERROR_ILL_CONFIG_BANK_EXT.exp();
			}
		} catch (Exception e1) {
			throw PayExceptionCode.ERROR_ILL_CONFIG_BANK_EXT.exp();
		}

		String fuiouBankNo = bankConfigExtPO.getBankNoExt();

		if (StringUtils.isBlank(fuiouBankNo) || fuiouBankNo.length() != 4) {
			logger.error(Log.op(op).msg("查询富友银行代码失败").kv("bankCode", req.getBankCode()).toString());
			return ValidResult.newInstance(false, "请求参数错误，不支持的银行代码");
		}

		try {
			EnterpriseAuth userAuthPO = enterpriseAuthService.queryByUserIdAndMerchantCode(req.getUserId(), merchantCode);
			if (userAuthPO != null) {
				// 如果实名信息存在,四要素 验证法人用户幂等
				if (enterpriseAuthService.checkEnterpriseOpenSuccess(merchantCode, req)) {
					return ValidResult.newInstance(true, PayConstants.OPEN_ACCOUNT_SUCCESS);
				}
			}
		} catch (Exception e) {
			logger.error(Log.op(op).msg("查询实名认证信息异常").kv("userId", req.getUserId()).kv("merchantCode", merchantCode).toString(), e);
		}

		return ValidResult.newInstance(true, null);
	}

	@Deprecated
	@Override
	public FuiouUserRegister normalUserRegister(UserRegisterReq req, String merchantCode) throws Throwable {
		final String op = "FuiouDepositRegisterServiceImpl.normalUserRegister";

		// 用户认证信息校验,add by jeff
		userAuthService.checkIdNoAndName(merchantCode, req.getUserId(), req.getIdCard(), req.getCustName());

		// 初始化订单或根据orderId和merchantCode查询
		FuiouUserRegister order = initUserRegister(req, merchantCode);

		// 更新订单
		// int i = userRegisterDao.updateStateByBusiId(FuiouDepositStateEnum.INI.getValue(), FuiouDepositStateEnum.DEALING.getValue(),
		// order.getBusiId(),
		// DateUtil.getCurrentDateTime());
		int i = userRegisterDao.updateStateByBusiId(order.getBusiId(), FuiouDepositStateEnum.DEALING.getValue(), FuiouDepositStateEnum.INI.getValue(),
				PayExceptionCode.PROCESSING.getCode(), PayExceptionCode.PROCESSING.getDesc());

		if (i > 0) {
			// 请求存管系统
			PayRspCodeVO payRspCodeVO = fuiouDepositService.normalUserRegister(order);

			// 处理返回结果
			handleUserRegisterResponse(payRspCodeVO, order, req);
		}

		// 根据订单最终的状态, 返回响应
		return userRegisterDao.selectByPrimaryKey(order.getBusiId());
	}

	@Override
	public FuiouUserRegister searchFuiouUserRegister(String merchantCode, UserRegisterReq userRegisterReq) {
		try {
			String idNoCip = CryptUtil.encrypt(userRegisterReq.getIdCard());
			String cardNoCip = CryptUtil.encrypt(userRegisterReq.getBankCardNo());
			return userRegisterDao.selectByFourElements(merchantCode, userRegisterReq.getUserId(), userRegisterReq.getCustName(), idNoCip, cardNoCip,
					userRegisterReq.getPhone(), 0);
		} catch (Exception e) {
			logger.warn(Log.op("FuiouDepositRegisterServiceImpl.searchFuiouUserRegister").toString(), e);
		}
		return new FuiouUserRegister();
	}

	/**
	 * 处理个人开户返回结果
	 *
	 * @author yejc
	 * @date 2017-09-30
	 * @since v2.0.0
	 */
	private void handleUserRegisterResponse(PayRspCodeVO resp, FuiouUserRegister order, UserRegisterReq req) {
		final String op = "FuiouDepositRegisterServiceImpl.handleUserRegisterResponse";
		// 超时
		if (PayExceptionCode.WARN_REQ_TIME_OUT.isCode(resp.getCode())) {
			logger.warn(Log.op(op).msg("个人用户开户请求超时").kv("busiId", order.getBusiId()).toString());
			// 超时处理
			commonService.saveNotifyTask(order.getMerchantCode(), req.getOrderId(), order.getBusiId(), FuiouBusiTypeEnum.REGISTER, "", null, "",
					new Date(), null);
		}

		if (PayExceptionCode.SUCCESS.isCode(resp.getCode())) {
			// 更新订单处理状态为成功
			userRegisterDao.updateStateAndRspByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), order.getBusiId(), DateUtil.getCurrentDateTime(),
					resp.getCode(), resp.getDesc());
			// 保存鉴权信息
			saveUserAuth(order.getMerchantCode(), order.getMerchantUserId(), req.getIdCard(), req.getCustName(), req.getBankCode(),
					req.getBankCardNo(), order.getPhone());
		} else {
			// 更新订单处理状态为失败
			userRegisterDao.updateStateAndRspByBusiId(FuiouDepositStateEnum.FAIL.getValue(), order.getBusiId(), DateUtil.getCurrentDateTime(),
					resp.getCode(), resp.getDesc());
		}
	}

	/**
	 * 保存鉴权信息
	 *
	 * @param merchantCode
	 * @param merchantUserId
	 * @param idCard
	 * @param customerName
	 * @param bankCode
	 * @param cardNo
	 * @param phone 开户手机号
	 */
	public void saveUserAuth(String merchantCode, String merchantUserId, String idCard, String customerName, String bankCode, String cardNo,
			String phone) {
		final String op = "FuiouDepositRegisterServiceImpl.saveUserAuth";
		try {
			BankConfigPO bankConfigPO = bankConfigService.queryByBankCode(bankCode);
			userAuthService.save(merchantCode, merchantUserId, idCard, customerName, PaymentEnum.FUIOU_DEPOSIT.getValue(), bankCode,
					bankConfigPO.getBankName(), cardNo, null, phone);
		} catch (Throwable throwable) {
			logger.error(Log.op(op).msg("开户后保存用户鉴权信息失败").kv("merchantCode", merchantCode).kv("merchantUserId", merchantUserId).toString(), throwable);
		}
	}

	public void saveEnterpriseAuth(String merchantCode, String merchantUserId, String companyName, String bankCode, String cardNo) {
		final String op = "FuiouDepositRegisterServiceImpl.saveEnterpriseAuth";
		try {
			enterpriseAuthService.save(merchantCode, merchantUserId, companyName, PaymentEnum.FUIOU_DEPOSIT.getValue(), bankCode, cardNo, null);
		} catch (Throwable throwable) {
			logger.error(Log.op(op).msg("开户后保存企业鉴权信息失败").kv("merchantCode", merchantCode).kv("merchantUserId", merchantUserId).toString(), throwable);
		}
	}

	@Override
	public FuiouArtificialRegister artificialUserRegister(ArtificialRegisterReq req, String merchantCode) throws Throwable {
		final String op = "FuiouDepositRegisterServiceImpl.artificialUserRegister";

		// 根据orderId和merchantCode查询或初始化订单
		FuiouArtificialRegister order = initArtificialRegister(req, merchantCode);

		// 更新订单
		// int i = artificialRegisterDao.updateStateByBusiId(FuiouDepositStateEnum.INI.getValue(), FuiouDepositStateEnum.DEALING.getValue(),
		// order.getBusiId(), DateUtil.getCurrentDateTime());

		int i = artificialRegisterDao.updateStateByBusiId(order.getBusiId(), FuiouDepositStateEnum.DEALING.getValue(),
				FuiouDepositStateEnum.INI.getValue(), PayExceptionCode.PROCESSING.getCode(), PayExceptionCode.PROCESSING.getDesc());

		if (i > 0) {
			// 请求存管系统
			PayRspCodeVO payRspCodeVO = fuiouDepositService.artificialRegister(order);

			// 处理返回结果
			handleArtificialRegisterResponse(payRspCodeVO, order, req);
		}
		// 根据订单最终的状态, 返回响应
		return artificialRegisterDao.selectByPrimaryKey(order.getBusiId());
	}

	@Override
	public FuiouArtificialRegister searchFuiouArtificialRegister(String merchantCode, ArtificialRegisterReq req) {
		try {
			String cardNoCip = CryptUtil.encrypt(req.getBankCardNo());
			return artificialRegisterDao.selectByFiveElements(merchantCode, req.getUserId(), req.getArtificialName(), req.getIdCard(), req.getPhone(),
					req.getCompanyName(), cardNoCip, null);
		} catch (Exception e) {
			logger.warn(Log.op("FuiouDepositRegisterServiceImpl.searchFuiouArtificialRegister").toString(), e);
		}
		return new FuiouArtificialRegister();
	}

	/**
	 * 处理法人开户返回结果
	 *
	 * @author yejc
	 * @date 2017-09-30
	 * @since v2.0.0
	 */
	private void handleArtificialRegisterResponse(PayRspCodeVO resp, FuiouArtificialRegister order, ArtificialRegisterReq req) {
		final String op = "FuiouDepositRegisterServiceImpl.handleArtificialRegisterResponse";
		// 超时
		if (PayExceptionCode.WARN_REQ_TIME_OUT.isCode(resp.getCode())) {
			logger.warn(Log.op(op).msg("法人用户开户请求超时").kv("busiId", order.getBusiId()).toString());
			// 超时处理
			commonService.saveNotifyTask(order.getMerchantCode(), req.getOrderId(), order.getBusiId(), FuiouBusiTypeEnum.ARTIFICIAL_REGISTER, "",
					null, "", new Date(), null);
		}

		if (PayExceptionCode.SUCCESS.isCode(resp.getCode())) {
			// 更新订单处理状态为成功
			artificialRegisterDao.updateStateAndRspByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), order.getBusiId(),
					DateUtil.getCurrentDateTime(), resp.getCode(), resp.getDesc());
			// 保存鉴权信息
			saveEnterpriseAuth(order.getMerchantCode(), order.getMerchantUserId(), req.getCompanyName(), req.getBankCode(), req.getBankCardNo());
		} else {
			// 更新订单处理状态为失败
			artificialRegisterDao.updateStateAndRspByBusiId(FuiouDepositStateEnum.FAIL.getValue(), order.getBusiId(), DateUtil.getCurrentDateTime(),
					resp.getCode(), resp.getDesc());
		}
	}

	/**
	 * 初始化订单或根据orderId和merchantCode查询
	 *
	 * @param req
	 * @param merchantCode
	 * @return
	 * @author yejc
	 * @throws Exception
	 * @date 2017-09-30
	 * @since v2.0.0
	 */
	private FuiouUserRegister initUserRegister(UserRegisterReq req, String merchantCode) throws Exception {
		final String op = "FuiouDepositRegisterServiceImpl.initUserRegister";
		boolean duplicateKeyFlag = false;

		FuiouUserRegister order = new FuiouUserRegister();
		order.setOrderTime(req.getOrderTime());
		order.setOrderId(req.getOrderId());
		order.setMerchantCode(merchantCode);
		order.setState(FuiouDepositStateEnum.INI.getValue());
		order.setTerminal(req.getTerminal());
		order.setMerchantUserId(req.getUserId());
		String now = DateUtil.getCurrentDateTime();
		order.setCreateTime(now);
		order.setUpdateTime(now);
		order.setBusiId(fuiouIdUtils.generateBusiId(FuiouBusiTypeEnum.REGISTER, merchantCode));
		order.setCustomerName(req.getCustName());
		order.setCertifTp(req.getCertificationType());
		try {
			order.setIdNoCip(CryptUtil.encrypt(req.getIdCard()));
			order.setCardNoCip(CryptUtil.encrypt(req.getBankCardNo()));
		} catch (Exception e) {
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		order.setPhone(req.getPhone());
		order.setEmail("");
		order.setCityCode(FuiouDepositConstant.CITY_CODE_BEIJING); // 默认为北京
		try {
			BankConfigExtPO bankConfigExtPO = bankConfigExtService.queryByThirdBankCode(req.getBankCode(), PaymentEnum.FUIOU_DEPOSIT.getValue());
			String fuiouBankNo = bankConfigExtPO.getBankNoExt();
			order.setBankCode(fuiouBankNo);
		} catch (Exception e1) {
			throw PayExceptionCode.ERROR_ILL_CONFIG_BANK_EXT.exp();
		}
		order.setBankName("");
		order.setPassword(req.getPassword());
		order.setLoginPassword(req.getLoginPassword());
		order.setRemark(req.getRemark());
		try {
			userRegisterDao.insert(order);
		} catch (DuplicateKeyException e) {
			logger.warn(Log.op(op).msg("订单已存在！").kv("orderId", order.getOrderId()).kv("merchantCode", merchantCode).toString(), e);
			duplicateKeyFlag = true;
		}

		if (duplicateKeyFlag) {
			order = userRegisterDao.selectByOrderIdMerchantCode(req.getOrderId(), merchantCode);
			if (order == null) {
				// 查询已有订单
				String idNoCip = CryptUtil.encrypt(req.getIdCard());
				String cardNoCip = CryptUtil.encrypt(req.getBankCardNo());
				order = userRegisterDao.selectByFourElements(merchantCode, req.getUserId(), req.getCustName(), idNoCip, cardNoCip, req.getPhone(),
						null);

				if (order == null) {
					logger.warn(Log.op(op).msg("保存普通用户开户订单，主键冲突没有找到相关订单信息").kv("UserRegisterReq", req).kv("merchantCode", merchantCode).toString());
				}
			}
		}
		return order;
	}

	/**
	 * 初始化订单或根据orderId和merchantCode查询
	 *
	 * @param req
	 * @param merchantCode
	 * @return
	 * @author yejc
	 * @throws Exception
	 * @date 2017-09-30
	 * @since v2.0.0
	 */
	private FuiouArtificialRegister initArtificialRegister(ArtificialRegisterReq req, String merchantCode) throws Exception {
		final String op = "FuiouDepositRegisterServiceImpl.initArtificialRegister";
		boolean duplicateKeyFlag = false;

		FuiouArtificialRegister order = new FuiouArtificialRegister();
		order.setOrderTime(req.getOrderTime());
		order.setOrderId(req.getOrderId());
		order.setMerchantCode(merchantCode);
		order.setState(FuiouDepositStateEnum.INI.getValue());
		order.setTerminal(req.getTerminal());
		order.setMerchantUserId(req.getUserId());
		String now = DateUtil.getCurrentDateTime();
		order.setCreateTime(now);
		order.setUpdateTime(now);
		order.setBusiId(fuiouIdUtils.generateBusiId(FuiouBusiTypeEnum.ARTIFICIAL_REGISTER, merchantCode));
		order.setCustomerName(req.getCompanyName());
		order.setArtificialName(req.getArtificialName());
		try {
			order.setIdNoCip(CryptUtil.encrypt(req.getIdCard()));
			order.setCardNoCip(CryptUtil.encrypt(req.getBankCardNo()));
		} catch (Exception e) {
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		order.setPhone(req.getPhone());
		order.setEmail("");
		order.setCityCode(FuiouDepositConstant.CITY_CODE_BEIJING); // 默认为北京
		try {
			BankConfigExtPO bankConfigExtPO = bankConfigExtService.queryByThirdBankCode(req.getBankCode(), PaymentEnum.FUIOU_DEPOSIT.getValue());
			String fuiouBankNo = bankConfigExtPO.getBankNoExt();
			order.setBankCode(fuiouBankNo);
		} catch (Exception e1) {
			throw PayExceptionCode.ERROR_ILL_CONFIG_BANK_EXT.exp();
		}
		order.setBankName("");
		order.setPassword(req.getPassword());
		order.setLoginPassword(req.getLoginPassword());
		order.setRemark(req.getRemark());
		try {
			artificialRegisterDao.insert(order);
		} catch (DuplicateKeyException e) {
			logger.warn(Log.op(op).msg("订单已存在！").kv("orderId", order.getOrderId()).kv("merchantCode", merchantCode).toString(), e);
			duplicateKeyFlag = true;
		}

		if (duplicateKeyFlag) {
			order = artificialRegisterDao.selectByOrderIdMerchantCode(req.getOrderId(), merchantCode);
			if (order == null) {
				// 查询已有订单
				String cardNoCip = CryptUtil.encrypt(req.getBankCardNo());
				order = artificialRegisterDao.selectByFiveElements(merchantCode, req.getUserId(), req.getArtificialName(), req.getIdCard(),
						req.getPhone(), req.getCompanyName(), cardNoCip, null);

				if (order == null) {
					logger.warn(
							Log.op(op).msg("保存企业开户订单，主键冲突没有找到相关订单信息").kv("ArtificialRegisterReq", req).kv("merchantCode", merchantCode).toString());
				}
			}
		}

		return order;
	}

	@Override
	public ValidResult validArtificialIdemptent(String merchantCode, String userId, String artificialName, String idNo, String phone,
			String enterpriseName, String bankCardNo) throws Exception {
		final String op = "FuiouDepositRegisterServiceImpl.validArtificialIdemptent";
		String idNoCip = CryptUtil.encrypt(idNo);
		String cardNoCip = CryptUtil.encrypt(bankCardNo);

		// step1.校验用户实名信息
		EnterpriseAuth userAuthPO = enterpriseAuthService.queryByUserIdAndMerchantCode(userId, merchantCode);
		if (userAuthPO == null) {
			// 如果用户实名信息不存在，则允许继续开户
			return ValidResult.newInstance(false);
		}

		// 如果实名信息存在，则校验一直性
		if (!StringUtils.equals(userAuthPO.getEnterpriseName(), enterpriseName) || !StringUtils.equals(userAuthPO.getCardNoCip(), cardNoCip)) {
			// 如果姓名和证件号码不一致，则终止流程
			return ValidResult.newInstance(true).errCode(PayRspCodeEnum.PAY_CODE_ID_NO_ERROR.getValue())
					.errMsg(PayRspCodeEnum.PAY_CODE_ID_NO_ERROR.getDisplay());
		}

		// 用户四要素一致，则表示已经开过户，返回幂等，响应已经开户
		ValidResult result = ValidResult.newInstance(true).errCode(PayRspCodeEnum.SUCCESS.getValue()).errMsg(PayRspCodeEnum.SUCCESS.getDisplay());

		// 如果成功，找到相关成功的开户记录的业务主键
		FuiouArtificialRegister artificialRegister = artificialRegisterDao.selectByFiveElements(merchantCode, userId, artificialName, idNoCip, phone,
				enterpriseName, cardNoCip, PayRspCodeEnum.SUCCESS.getValue());
		if (artificialRegister != null) {
			result.ext(artificialRegister.getBusiId());
		} else {
			logger.error(Log.op(op).msg("【富友存管企业用户开户】开户幂等，幂等响应开户成功，查询用户开户成功订单信息为空").kv("merchantCode", merchantCode).kv("userId", userId)
					.kv("enterpriseName", enterpriseName).kv("cardNoCip", bankCardNo).toString());
		}

		logger.info(Log.op(op).msg("【富友存管企业用户开户】已经存在开户信息，且开户信息一致，走幂等流程。").kv("merchantCode", merchantCode).kv("userId", userId)
				.kv("name", enterpriseName).kv("cardNoCip", cardNoCip).toString());

		return result;
	}

	@Override
	public ArtificialRegisterVO saveArtificialRegister(String merchantCode, ArtificialRegisterReq req) throws Exception {
		final String op = "FuiouDepositRegisterServiceImpl.initArtificialRegister";
		boolean duplicateKeyFlag = false;

		String cardNoCip = CryptUtil.encrypt(req.getBankCardNo());
		String idNoCip = CryptUtil.encrypt(req.getIdCard());

		FuiouArtificialRegister order = new FuiouArtificialRegister();
		order.setOrderTime(req.getOrderTime());
		order.setOrderId(req.getOrderId());
		order.setMerchantCode(merchantCode);
		order.setState(FuiouDepositStateEnum.INI.getValue());
		order.setTerminal(req.getTerminal());
		order.setMerchantUserId(req.getUserId());
		String now = DateUtil.getCurrentDateTime();
		order.setCreateTime(now);
		order.setUpdateTime(now);
		order.setBusiId(fuiouIdUtils.generateBusiId(FuiouBusiTypeEnum.ARTIFICIAL_REGISTER, merchantCode));
		order.setCustomerName(req.getCompanyName());
		order.setArtificialName(req.getArtificialName());

		order.setIdNoCip(idNoCip);
		order.setCardNoCip(cardNoCip);

		order.setPhone(req.getPhone());
		order.setEmail("");
		order.setCityCode(FuiouDepositConstant.CITY_CODE_BEIJING); // 默认为北京
		order.setBankCode(req.getBankCode());
		order.setBankName("");
		order.setPassword(req.getPassword());
		order.setLoginPassword(req.getLoginPassword());
		order.setRemark(req.getRemark());
		try {
			artificialRegisterDao.insert(order);
		} catch (DuplicateKeyException e) {
			logger.warn(Log.op(op).msg("订单已存在！").kv("orderId", order.getOrderId()).kv("merchantCode", merchantCode).toString(), e);
			duplicateKeyFlag = true;
		}

		if (duplicateKeyFlag) {
			order = artificialRegisterDao.selectByOrderIdMerchantCode(req.getOrderId(), merchantCode);
			if (order == null) {
				// 查询已有订单
				order = artificialRegisterDao.selectByFiveElements(merchantCode, req.getUserId(), req.getArtificialName(), idNoCip,
						req.getPhone(), req.getCompanyName(), cardNoCip, null);

				if (order == null) {
					logger.warn(
							Log.op(op).msg("保存企业开户订单，主键冲突没有找到相关订单信息").kv("ArtificialRegisterReq", req).kv("merchantCode", merchantCode).toString());
				}
			}
		}

		return ArtificialRegisterVO.newInstance(order);
	}

	@Override
	public FuiouArtificialRegister artificialUserRegister(ArtificialRegisterVO vo) {
		final String op = "FuiouDepositRegisterServiceImpl.artificialUserRegister";

		FuiouArtificialRegister po = vo.getPo();

		// 更新订单状态为处理中
		int i = artificialRegisterDao.updateStateByBusiId(po.getBusiId(), FuiouDepositStateEnum.DEALING.getValue(),
				FuiouDepositStateEnum.INI.getValue(), PayExceptionCode.PROCESSING.getCode(), PayExceptionCode.PROCESSING.getDesc());
		if (i <= 0) {
			// 如果更新没有命中，说明可能存在并发的情况，或者重复请求
			logger.warn(Log.op(op).msg("【富友存管企业用户开户】更新订单状态为处理中，更新命名中，直接返回订单结果状态").kv("busiId", po.getBusiId()).toString());
			return artificialRegisterDao.selectByPrimaryKey(po.getBusiId());
		}

		Integer rspCode = null;
		String rspMsg = "";
		String state = FuiouDepositStateEnum.FAIL.getValue();

		try {
			// 请求富友存管开户接口
			PayRspCodeVO payRsp = fuiouDepositService.artificialRegister(po);

			if (PayExceptionCode.WARN_REQ_TIME_OUT.isCode(payRsp.getCode()) || PayExceptionCode.TO_CONFIRM.isCode(payRsp.getCode())) {
				state = FuiouDepositStateEnum.DEALING.getValue();

				// 如果响应结果是超时或者待确认，则生成查询策略
				commonService.saveQueryTask(po.getMerchantCode(), po.getBusiId(), FuiouBusiTypeEnum.ARTIFICIAL_REGISTER);
			} else if (PayExceptionCode.SUCCESS.isCode(payRsp.getCode())) {
				// 如果响应结果成功，更新用户鉴权信息
				state = FuiouDepositStateEnum.SUCCESS.getValue();

				// 保存鉴权信息
				saveEnterpriseAuth(po.getMerchantCode(), po.getMerchantUserId(), po.getCustomerName(), po.getBankCode(),
						CryptUtil.decrypt(po.getCardNoCip()));
			}

			rspCode = payRsp.getCode();
			rspMsg = payRsp.getDesc();
		} catch (PayException e) {
			rspCode = e.getCode();
			rspMsg = e.getMessage();
		} catch (Exception e) {
			logger.error(Log.op(op).msg("【富友存管企业用户开户】请求富友接口发生未知异常").kv("busiId", po.getBusiId()).toString(), e);
			rspCode = PayExceptionCode.WARN_UNKNOWN.getCode();
			rspMsg = PayExceptionCode.WARN_UNKNOWN.getDesc();
		}

		artificialRegisterDao.updateStateAndRspByBusiId(state, po.getBusiId(), DateUtil.getCurrentDateTime(), rspCode, rspMsg);

		po.setState(state);
		po.setRespCode(rspCode);
		po.setRespDesc(rspMsg);

		return po;
	}
}
